/* !
 * Tog JavaScript Library v0.1 (beta)
 * http://www.tog2html.com
 *
 * Copyright 2011, Liangliang Zheng (jsPop)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * OFFICIAL HOME : http://www.tog2html.com
 *
 *
 * Date: Sat June 12 2011 
 */
(function(){

    var hash_map = {
        '&':'&amp;',
        '  ': ' &nbsp;',
        '<':'&lt;',
        '>':'&gt;'
    }

    function  html_escape(string, quote) {
        var symbol = '', tmp_str = '', entity = '';
        if(typeof(string)== 'undefined' || string == null) return null;
        tmp_str = string.toString();

        for (symbol in hash_map) {
            entity = hash_map[symbol];
            tmp_str = tmp_str.split(symbol).join(entity);
        }
        if(quote){
            tmp_str = tmp_str.split('"').join('&quot;');
            tmp_str = tmp_str.split("'").join('&#39;');
        }
        return tmp_str;
    }

    var exp_tag = /^[a-zA-Z][\w_]*/;
    var exp_tagExtra = /([\.\#\$\&\?])([\w_-]*)/g;

    function tog_clone(t){
        var newT = {
            cls: {}
        }
        if('tag' in t) newT.tag = t.tag;
        if('name' in t) newT.name = t.name;
        if('id' in t) newT.id = t.id;
        if('type' in t) newT.type = t.type;
        if('anc' in t) newT.anc = t.anc;

        for(var i in t.cls){
            newT.cls[i] = 1;
        }
        return newT
    }

    var cacheTogStr = {
        length :0
    };
    var togCacheNumber = 299;
    function tog_putCacheTogStr(tagStr, t){
        if(tagStr == 'length')
            return;
        cacheTogStr[tagStr] = tog_clone(t);
        cacheTogStr.length ++;
        if(cacheTogStr.length > togCacheNumber){ // cache 300 tag strs
            var j = 0;
            for(var i in cacheTogStr){
                if(j++ > 0){
                    cacheTogStr.length --;
                    delete cacheTogStr[i];
                    return;
                }
            }
        }
    }
    function tog_getCacheTogStr(tagStr){
        if(tagStr in cacheTogStr){
            return tog_clone(cacheTogStr[tagStr]);
        } else{
            return null;
        }
    }
    function tog_pushTogExtra(type, content, t){
        switch(type){
            case '.':
                t.cls[content] = 1;
                break;
            case '#':
                t.id = content;
                break;
            case '&':
                t.type = content;
                break;
            case '$':
                t.name = content;
                break;
            case '?':
                t.anc = content;
                break;
        }
    }

    function tog_parse_params(tagStrParts, args){
        if(args == null) return;
        
        for(var ind = 0; ind < args.length; ind++){
            var arg = args[ind];
            var type = typeof arg;
            switch(type){
                case 'object':
                    if(arg == null)
                        continue;
                    if(arg instanceof Array){
                        tog_parse_params(tagStrParts, arg);
                    } 
                    break;
                case 'string': case 'number': case 'boolean':
                    tagStrParts[tagStrParts.length] = arg;
                    break;
            }
        // end of each args
        }
    }

    /**
     * <pre>
     * tagStr - table#some_id.some_class$some_name&some_type
     * return the object
     * {tag, name, id, cls:{}, type}
     *
     */
    function tog_parseTogStrUnit(tagStr){
        var t = tog_getCacheTogStr(tagStr);
        if(t != null){
            return t;
        }
        var res = exp_tag.exec(tagStr);
        if(res == null){
            t = {
                cls: {}
            };
        } else {
            t = {
                tag: res['0'],
                cls: {}
            };
        }


        var lastType = [];
        while(true){
            res = exp_tagExtra.exec(tagStr);
            if(res == null){
                tog_putCacheTogStr(tagStr, t);
                return t;
            }
            if(res['2'] != ''){
                if(lastType.length > 0){
                    for(var i = 0; i < lastType.length; i ++ ){
                        tog_pushTogExtra(lastType[i], res['2'], t);
                    }
                    lastType = [];
                }
                tog_pushTogExtra(res['1'], res['2'], t);
            } else {
                lastType.push(res['1']);
            }
        }
    }

    function clone_copyArray(o){
        var n = [];
        for(var i = 0; i < o.length; i++){
            n[i] = o[i];
        }
        return n;
    }

    function clone_copyObject(o){
        var n = {};
        for(var k in o){
            if(o.hasOwnProperty(k)){
                n[k] = o[k];
            }
        }
        return n;
    }

    var html_emptyTags ={
        'br':1,
        'hr':1,
        'meta':1,
        'link':1,
        'base':1,
        'img':1,
        'embed':1,
        'param':1,
        'area':1,
        'col':1,
        'input':1
    }

    var html_no_extraSpace = {
        'i':1,
        'em':1,
        'strong':1,
        'b':1,
        'font':1,
        'span':1
    }

    function htmlIndentation(level){
        var str = '  ';
        return new Array( level ).join( str );
    }
    
    function skip_arguments(inputArgs, start){
        if(start >= inputArgs.length){
            return null;
        }
        var args = [];
        for(var i = start; i < inputArgs.length; i++){
            args[args.length] = inputArgs[i];
        }
        return args;
    }

    var bIndentation = false;
    var bNewline = false;
    _tog = function(tagStr, parent){
        this.t = tog_parseTogStrUnit(tagStr);
        if(!parent) this._parent = null;
        else this._parent = parent;
        this.content = [];
    }

    tog = _tog.prototype = {
        _copyIds: function(ids){
            var root = this;
            for(var i in ids){
                if(ids.hasOwnProperty(i)){
                    root._ids[i] = ids[i];
                }
            }
        },
        _copyAncs: function(ancs){
            var root = this;
            for(var i in ancs){
                if(ancs.hasOwnProperty(i)){
                    root._ancs[i] = ancs[i];
                }
            }
        },
        close: function(targetStr){
            if(this._isLeaf){
                this._isLeaf = false;
                this.up();
                if(targetStr == undefined) return this;
            }
            if(targetStr == undefined){
                this.up();
            }
            var targets = targetStr.split(/ +/);
            for(var i = 0; i < targets.length; i++){
                var togObj = tog_parseTogStrUnit(targets[i]);
                while(true){
                    if(this._isMatchCond(togObj)){
                        this.curr = this.curr._parent;
                        break;
                    }
                    if(this.curr._parent == null) break;
                    this.curr = this.curr._parent;
                }
                if(this.curr._parent == null) break;// reach the root, no need to process further
            }
            return this;
        },
        up: function(targetStr){
            var type = typeof targetStr;
            if(this._isLeaf){
                this._isLeaf = false;
                this.up();
            }
            if(targetStr == undefined){
                // first we go up a level
                if(this.curr._parent != null){
                    this.curr = this.curr._parent;
                }
                
                // if the current tag is an empty tag, go up until it is not an empty tag
                while(this.curr._emp && this.curr._parent != null){
                    this.curr = this.curr._parent;
                }
                if(targetStr == undefined) return this;
            } else if(type == 'string'){
                var targets = targetStr.split(/ +/);
                for(var i = 0; i < targets.length; i++){
                    var togObj = tog_parseTogStrUnit(targets[i]);
                    while(true){
                        if(this._isMatchCond(togObj) || this.curr._parent == null){
                            break;
                        }
                        if(this.curr._parent == null)break;
                        this.curr = this.curr._parent;
                    }
                    if(this.curr._parent == null)break; // not need to process further
                }
            } else {
                for(i = 0; i < targetStr && this.curr._parent != null; i++){
                    this.curr = this.curr._parent;
                    // if the current tag is an empty tag, go up until it is not an empty tag
                    while(this.curr._emp && this.curr._parent != null){
                        this.curr = this.curr._parent;
                    }
                }
            }
            return this;
        },
        _isMatchCond: function(togObj){
            var t = this.curr.t;
            if('tag' in togObj && (!('tag' in t) || togObj.tag != t.tag)){
                return false;
            }
            if('id' in togObj && (!('id' in t) || togObj.id != t.id)){
                return false;
            }
            if('anc' in togObj && (!('anc' in t) || togObj.anc != t.anc)){
                return false;
            }
            if('name' in togObj && (!('name' in t) || togObj.name != t.name)){
                return false;
            }
            if('type' in togObj && (!('type' in t) || togObj.type != t.type)){
                return false;
            }
            for(var i in togObj.cls){
                if(togObj.cls.hasOwnProperty(i) && !(i in t.cls)){
                    return false;
                }
            }
            return true;
        }
        ,
        _isThisMatchCond: function(togObj){
            var t = this.t;
            if('tag' in togObj && (!('tag' in t) || togObj.tag != t.tag)){
                return false;
            }
            if('id' in togObj && (!('id' in t) || togObj.id != t.id)){
                return false;
            }
            if('anc' in togObj && (!('anc' in t) || togObj.anc != t.anc)){
                return false;
            }
            if('name' in togObj && (!('name' in t) || togObj.name != t.name)){
                return false;
            }
            if('type' in togObj && (!('type' in t) || togObj.type != t.type)){
                return false;
            }
            for(var i in togObj.cls){
                if(togObj.cls.hasOwnProperty(i) && !(i in t.cls)){
                    return false;
                }
            }
            return true;
        }
        ,
        Tog: function(input){
            if(!this.hasOwnProperty('_ids') ){
                return Tog.apply(null, arguments);
            }
            var tagStrParts = [] // tag string
            , tag;
            
            if(input == true){
                tag = arguments[1];
                tog_parse_params(tagStrParts, arguments[2]);
            } else{
                tog_parse_params(tagStrParts, arguments);
            }

            if(this._isLeaf){
                this._isLeaf = false;
                this.up();
            }
            var fullTagStr = tagStrParts.join('');

            // the / is for separating the closing tag string and the new tag string
            if(typeof fullTagStr == 'string'){
                var tagStrs = fullTagStr.split('/');
            }
            if(tagStrs.length > 1){
                var closeTagStr = tagStrs[0];
                if(closeTagStr.replace(/^ +$/, '') == ''){
                    this.up();
                } else {
                    this.close(closeTagStr);
                }
                // gonna close the tag

                var newTagStr = tagStrs[1];
            } else {
                newTagStr = tagStrs[0];
            }
            var _curr = this.curr;

            // creating a new tag and append to the current tag
            // the current curr will be replaced to the the new tag
            var newTag = new _tog(newTagStr, _curr);
            newTag._root = this;
            this.curr = newTag;
            if('id' in newTag.t){
                this._ids[newTag.t.id] = newTag;
            }
            if('anc' in newTag.t){
                this._ancs[newTag.t.anc] = newTag;
            }
            if(tag){
                newTag.t.tag = tag;
            }
            _curr.content.push(newTag);
            return this;
        },
        tog:function(input){
            var t = this.Tog.apply(this, arguments);
            t._isLeaf = true;
            return t;
        },
        astr: function(attr1, attr2){
            var t= this.curr.t;
            for(var i = 0; i < arguments.length; i++){
                var attr = arguments[i];
                // if the input is a string, simply put it in attrStr
                if(!t.attrStr){
                    t.attrStr = [];
                }
                t.attrStr.push(attr);
            }
            return this;
        },
        attr: function(attr, value){
            var t= this.curr.t;
            // if the input is an object
            // we will treat every key in the object as the name of the attribute name
            if(!('attrs' in t)){
                t.attrs = {};
            }
            // if attr is a string, regard it as attr name
            if(typeof attr == 'string'){
                if(arguments.length > 2){
                    var vals = [];
                    for(var i = 1; i < arguments.length; i++){
                        vals[vals.length] = arguments[i];
                    }
                    t.attrs[attr] = vals.join('');
                } else {
                    if(value == undefined || value == null)
                        value = '';
                    t.attrs[attr] = value;
                }
            } else {
                for(var attrName in attr){
                    if(attr.hasOwnProperty(attrName)){
                        t.attrs[attrName] = attr[attrName];
                    }
                }
            }
            return this;
        },
        removeAttr:function(key){
            var t = this.curr.t;
            if(typeof key != 'object'){
                key = key.split(/ +/);
            }
            for(var i = 0; i < key.length; i++){
                delete t.attrs[key[i]];
            }
            return this;
        },
        cont: function(content1, content2){
            if(this.hasOwnProperty('_ids')){
                var t = this;
            } else {
                t = Tog();
            }
            var curr = t.curr;
            for(var i = 0; i < arguments.length; i++){
                var content = arguments[i];
                curr.content.push(content);
                // if the content is a tag object
                // configure it and join the ids into the root tag object
                if(typeof content == 'object' && content != null && '_root' in content){
                    content = content._root;
                    content._parent = t.curr;
                    content._root = t;
                    t._copyIds(content._ids);
                    t._copyAncs(content._ancs);
                }
            }
            return t;
        },
        Cont: function(content1, content2){
            if(this instanceof _tog){
                this.close();
            }
            return this.cont.apply(this, arguments);
        },
        raw:function(content1, content2){
            var curr = this.curr;
            for(var i = 0; i < arguments.length; i++){
                var content = arguments[i];
                curr.content.push(html_escape(content));
            }
            return this;
        },
        sstr: function(style1, style2){
            var t= this.curr.t;
            for(var i = 0; i < arguments.length; i++){
                var style = arguments[i];
                if(!t.styleStr){
                    t.styleStr = [];
                }
                t.styleStr.push(style);
            }
            return this;
        },
        style: function(style, value){
            var t= this.curr.t;
            // if the input is an object
            // we will treat every key in the object as the name of the style name
            if(!t.styles){
                t.styles = {};
            }
            // if the input is a string, simply put it in styleStr
            if(typeof style == 'string'){
                if(arguments.length > 2){
                    var vals = [];
                    for(var i = 1; i < arguments.length; i++){
                        vals[vals.length] = arguments[i];
                    }
                    t.styles[style] = vals.join('');
                } else {
                    t.styles[style] = value;
                }
            } else {
                for(var styleName in style){
                    if(style.hasOwnProperty(styleName)){
                        t.styles[styleName] = style[styleName];
                    }
                }
            }
            return this;
        },
        cls: function(clsStr){
            var t = this.curr.t;
            var classes = clsStr.split(/ +/);
            for(var i = 0; i < classes.length; i++){
                if(classes.hasOwnProperty(i) && classes[i] != ''){
                    t.cls[classes[i]] = 1;
                }
            }
            return this;
        },
        id: function(id){
            delete this._ids[this.t.id];
            this.curr.t.id = id;
            this._ids[id] = this;
            return this;
        },
        anc: function(anc){
            delete this._ids[this.t.id];
            this.curr.t.anc = anc;
            this._ancs[anc] = this;
            return this;
        },
        name: function(name){
            this.curr.t.name = name;
            return this;
        },
        type: function (type){
            this.curr.t.type = type;
            return this;
        },
        emp:function(fullTagStr){
            if(!fullTagStr) fullTagStr = ' ';
            this.Tog(fullTagStr);
            this.curr._emp = 1;
            return this;
        },
        html: function(indent, newline){
            // if there is indentation for the html generated
            if(indent == undefined) indent = bIndentation;
            // if the generated html is armed with new lines
            if(newline == undefined) newline = bNewline;

            var htmlText = [];
            this._htmlStr(indent, newline, 0, htmlText);
            var last = htmlText.length - 1;
            var c = '\n';
            while(c == '\n'){
                c = htmlText[last];
                if(c == '\n') delete htmlText[last];
                last --;
            }
            return htmlText.join('');
        },
        _htmlStr: function(indent, newline, level, h){
            if(!('_emp' in this)){
                var t = this.t;
                var no_extraSpace = t.tag in html_no_extraSpace;
                if(!no_extraSpace) h[h.length] = htmlIndentation(level);
                h[h.length] = '<';
                h[h.length] = t.tag;
                if('id' in t){
                    h[h.length] = ' id="';
                    h[h.length] = t.id;
                    h[h.length] = '"';
                }
                if('name' in t){
                    h[h.length] = ' name="';
                    h[h.length] = t.name;
                    h[h.length] = '"';
                }
                if('type' in t){
                    h[h.length] = ' type="';
                    h[h.length] = t.type;
                    h[h.length] = '"';
                }
                var hasCls = false;
                for(var key in t.cls){
                    hasCls = true;
                    break;
                }
                if(hasCls){
                    h[h.length] = ' class="';
                    var f = true;
                    for(key in t.cls){
                        if(t.cls.hasOwnProperty(key)){
                            if(f) f = false;
                            else h[h.length] = ' ';
                            h[h.length] = key;
                        }
                    }
                    h[h.length] = '"';
                }
                if('attrStr' in t){
                    h[h.length] = ' ';
                    h[h.length] = t.attrStr.join(' ');
                }
                if('attrs' in t){
                    f = true;
                    for(key in t.attrs){
                        if(t.attrs.hasOwnProperty(key)){
                            if(f) {
                                h[h.length] = ' ';
                                f = false;
                            } else {
                                h[h.length] = '" ';
                            }
                            h[h.length] = key;
                            h[h.length] = '="';
                            h[h.length] = t.attrs[key];
                        }
                    }
                    if(!f) h[h.length] = '"';
                }
                if('styleStr' in t || 'styles' in t){
                    h[h.length] = ' style="';
                    if('styleStr' in t){
                        h[h.length] = t.styleStr.join(';');
                        h[h.length] = ';';
                    }
                    if('styles' in t){
                        for(key in t.styles){
                            if(t.styles.hasOwnProperty(key)){
                                h[h.length] = key;
                                h[h.length] = ':';
                                h[h.length] = t.styles[key];
                                h[h.length] = ';';
                            }
                        }
                    }
                    h[h.length] = '"';
                }
                if(t.tag in html_emptyTags){
                    h[h.length] = '/>';
                    if(newline && !no_extraSpace) h[h.length] = '\n';
                    return;
                } else {
                    h[h.length] = '>';
                }
            // end of if emp not in t
            }
            var content = this.content;
            for(var i = 0; i < content.length; i++){
                if(typeof content[i] == 'object' && content[i] != null && '_htmlStr' in content[i]){
                    if(newline && h.length > 0 && h[h.length-1] != '\n' && !('_emp' in content[i]) && !(content[i].t.tag in html_no_extraSpace)) h[h.length] = '\n';
                    content[i]._htmlStr(indent, newline, level+1, h)
                } else {
                    h[h.length] = content[i];
                }
            }
            if(!('_emp' in this)){
                if(h[h.length-1] == '\n') h[h.length] = htmlIndentation(level);
                h[h.length] = '</';
                h[h.length] = t.tag;
                h[h.length] = '>';
                if(newline && !no_extraSpace) h[h.length] = '\n';
            }
        },
        clearCache: function(){
            cacheTogStr = {
                length: 0
            };
            return this;
        },
        setConfig: function(config){
            if('indent' in config){
                bIndentation = config.indent;
            }
            if('newline' in config){
                bNewline = config.newline;
            }
            if('cacheNum' in config){
                togCacheNumber = config.cacheNum;					
                var j = 0;
                var tmp = {
                    length: 0
                };
                for(var i in cacheTogStr){
                    if(tmp.length < togCacheNumber){ // cache 300 tag strs
                        if(j++ > 0){
                            tmp.length ++;
                            tmp[i] = cacheTogStr[i];
                        } else {
                            break;
                        }
                    }
                }
                cacheTogStr = tmp;
            }
            return this;
        },
        getById: function(id){
            if(id in this._ids){
                this.curr = this._ids[id];
                this._isLeaf = false;
            }
            return this;
        },
        getByAnc:function(anc){
            if(anc in this._ancs){
                this.curr = this._ancs[anc];
                this._isLeaf = false;
            }
            return this;
        },
        clearExtra: function(extra){
            var t = this.curr.t;
            if(extra.indexOf('c') != -1){
                t.cls = {};
            }
            if(extra.indexOf('i') != -1){
                delete t.id;
            }
            if(extra.indexOf('t') != -1){
                delete t.type;
            }
            if(extra.indexOf('n') != -1){
                delete t.name
            }
            if(extra.indexOf('a') != -1){
                delete t.attrStr;
                delete t.attrs;
            }
            if(extra.indexOf('s') != -1){
                delete t.styleStr;
                delete t.styles;
            }
            return this;
        },
        clear: function(id){
            if(id == undefined){
                target = this.curr;
            } else if(id in this._root._ids){
                var target = this._root._ids[id];
            } else {
                return this;
            }
            var content = target.content;
            for(var i = 0; i < content.length; i++){
                if(typeof content[i] == 'object' && content[i] != null && 'clear' in content[i]){
                    content[i].clear();
                    if(content[i].t.id){
                        delete content[i]._root._ids[content[i].t.id];
                    }
                }
            }
            target.content = {};
            this.curr = target;
            return this;
        }
        // ------------------ EXTENTION FUNCS
        ,
        root: function(){
            this.curr = this;
            return this;
        },
        find: function(matchStr){

            // start from the root
            if(matchStr.charAt(0) == '/'){
                var start = this;
                // removing the first char
                matchStr = matchStr.substr(1);
            } else {
                start = this.curr;
            }
            var rawMatches = matchStr.split(/ +/);
            var matches = [];
            for(var i = 0; i < rawMatches.length; i++){
                matches[matches.length++] = tog_parseTogStrUnit(rawMatches[i]);
            }
            
            // parse matchStr to objs
            // and use _find for finding the tog
            
            var _new = start._find(matches, 0);
            if(_new){
                // if the target cannot be found, set back the cursor
                this.curr = _new;
                this._isLeaf = false;
            }
            return this;
        },
        _find: function(matches, index){
            if(this._isThisMatchCond(matches[index])){
                index++;
                if(index == matches.length){
                    return this;
                }
            }
            for(var i = 0; i < this.content.length; i++){
                var child = this.content[i];
                if(typeof child == 'object' && child != null && '_find' in child){
                    var res = child._find(matches, index);
                    if(res){
                        return res;
                    }
                }
            }
            return false;
        },
        clone: function(){
            return this._clone(null, null, this.curr, null, null);
        },
        _clone: function(parent, root, curr, _ids, _ancs){
            var newT = new _tog('', parent);

            // assigning the basic tag info
            var t = this.t;
            var r = newT.t = tog_clone(t);
            if(t.attrs) r.attrs = clone_copyObject(t.attrs);
            if(t.attrStr) r.attrStr = clone_copyArray(t.attrStr);
            if(t.styles) r.styles = clone_copyObject(t.styles);
            if(t.styleStr) r.styleStr = clone_copyArray(t.styleStr);

            // set the root to the new tog
            if(root == null){
                newT._root = root = newT;
                _ids = newT._ids = {};
                _ancs = newT._ancs = {};
            } else {
                newT._root = root;
            }

            // if the cursor is on current tog, set the new cursor on this clone object
            if(curr === this){
                newT._root.curr = newT;
            }
            if(this._emp){
                newT._emp = 1
            }

            // cloning the contents
            for(var k = 0; k < this.content.length; k++){
                if(this.content.hasOwnProperty(k)){
                    var child = this.content[k];
                    if(typeof child == 'object' && child != null && ('clone' in child || '_clone' in child)){
                        if('Tog' in child){
                            child = child._clone(newT, root, curr, _ids, _ancs);
                        } else {
                            child = child.clone();
                        }
                    }
                    newT.content.push(child);
                }
            }
            return newT;
        },
        // -------- special style
        hide: function(){
            return this.style('display', 'none');
        },
        // -------- special attributes
        val: function(value){
            return this.attr('value', html_escape(value, true));
        },
        width: function(width){
            return this.attr('width', width);
        },
        height: function(height){
            return this.attr({
                height: height
            });
        },
        src: function(src){
            return this.attr({
                src: src
            });
        },
        alt: function(alt){
            return this.attr({
                alt: alt
            });
        },
        href: function(href){
            return this.attr({
                href:href
            });
        },
        rel:function(rel){
            return this.attr({
                rel:rel
            });
        },
        checked:function(checked){
            if(checked == undefined) checked = true;
            if(checked){
                return this.attr('checked', '');
            } else {
                return this.removeAttr('checked');
            }
        },
        disabled:function(disabled){
            if(disabled == undefined) disabled = true;
            if(disabled){
                return this.attr('disabled', '');
            } else{
                return this.removeAttr('disabled');
            }
        },
        colspan: function(cols){
            return this.attr('colspan', cols);
        },
        rowspan: function(rows){
            return this.attr('rowspan', rows);
        },
        cols: function(cols){
            return this.attr('cols', cols);
        },
        rows: function(rows){
            return this.attr('rows', rows);
        },
        size: function(size){
            return this.attr('size', size);
        },
        // -------- inputs
        input: function(fullTagStr, value, type){
            if(!type) type = 'text';
            if(!value) value = '';
            var t = this.Tog(true, 'input', fullTagStr);
            t.attr({
                value: html_escape(value, true),
                type: type
            });
            t._isLeaf = true; // if _isLeaf , close prev tog, when new tog is creating
            return t;
        },
        hidden: function(fullTagStr, value){
            return this.input(fullTagStr, value, 'hidden');
        },
        text: function(fullTagStr, value, size){
            var t = this.input(fullTagStr, value, 'text');
            if(size != undefined) t.size(size);
            return t;
        },
        button: function(fullTagStr, value){
            return this.input(fullTagStr, value, 'button');
        },
        radio: function(fullTagStr, value, checked){
            var t = this.input(fullTagStr, value, 'radio');
            if(checked) t.checked();
            return t;
        },
        checkbox: function(fullTagStr, value, checked){
            var t = this.input(fullTagStr, value, 'checkbox');
            if(checked) t.checked();
            return t;
        },
        // ---------- special
        cmt: function(comment){
            return this.cont('<!-- ', comment, ' -->');
        },
        // ---------- tags
        Table: function(param){
            return this.Tog(true, 'table', arguments);
        },
        Tr: function(param){
            return this.Tog(true, 'tr', arguments);
        },
        Td: function(param){
            return this.Tog(true, 'td', arguments);
        },
        td: function(param){
            var t = this.Tog(true, 'td', arguments);
            t._isLeaf = true;
            return t;
        },
        B: function(content){
            var t = this.Tog(true, 'b', null);
            return t.cont.apply(t, arguments);
        },
        b: function(content){
            var t = this.B.apply(this, arguments);
            t._isLeaf = true;
            return t;
        },
        Strong: function(content){
            var t = this.Tog(true, 'strong', null);
            return t.cont.apply(t, arguments);
        },
        strong: function(content){
            var t = this.Strong.apply(this, arguments);
            t._isLeaf = true;
            return t;
        },
        Em: function(content){
            var t = this.Tog(true, 'em', null);
            return t.cont.apply(t, arguments);
        },
        em: function(content){
            var t = this.Em.apply(this, arguments);
            t._isLeaf = true;
            return t;
        },
        I: function(content){
            var t = this.Tog(true, 'i', null);
            return t.cont.apply(t, arguments);
        },
        i: function(content){
            var t = this.I.apply(this, arguments);
            t._isLeaf = true;
            return t;
        },
        Th: function(param){
            return this.Tog(true, 'th', arguments);
        },
        th: function(param){
            var t = this.Tog(true, 'th', arguments);
            t._isLeaf = true;
            return t;
        },
        Textarea: function(param){
            return this.Tog(true, 'textarea', arguments);
        },
        textarea: function(param){
            var t = this.Tog(true, 'textarea', arguments);
            t._isLeaf = true;
            return t;
        },
        img: function(src, alt){
            var t = this.Tog(true, 'img', skip_arguments(arguments, 2));
            if(src != undefined) t.src(src);
            if(alt != undefined) t.alt(alt);
            t._isLeaf = true;
            return t;
        },
        Div: function(param){
            return this.Tog(true, 'div', arguments);
        },
        div: function(param){
            var t = this.Tog(true, 'div', arguments);
            t._isLeaf = true;
            return t;
        },
        Span: function(param){
            return this.Tog(true, 'span', arguments);
        },
        span: function(param){
            var t = this.Tog(true, 'span', arguments);
            t._isLeaf =true;
            return t;
        },
        Script: function(lang, src){
            var t = this.Tog(true, 'script', null);
            if(lang) {
                t.attr('language', lang);
            } else {
                t.attr('language', 'text/javascript');
            }
            if(src) t.href(src);
            return t;
        },
        br: function(){
            return this.Tog(true, 'br', null).up();
        },
        hr: function(){
            return this.Tog(true, 'hr', arguments).up();
        },
        Select: function(){
            return this.Tog(true, 'select', arguments);
        },
        Option: function(value, content, selected){
            var t = this.Tog(true, 'option', skip_arguments(arguments, 3));
            if(value != undefined && value != null) t.val(value);
            if(selected) t.attr({
                selected: ''
            });
            t.cont(content);
            return t;
        },
        option: function(value, content, selected){
            var t = this.Tog(true, 'option', skip_arguments(arguments, 3));
            if(value != undefined && value != null) t.val(value);
            if(selected) t.attr({
                selected: ''
            });
            t.cont(content);
            t._isLeaf = true;
            return t;
        },
        Ul: function(param){
            return this.Tog(true, 'ul', arguments);
        },
        Li: function(param){
            return this.Tog(true, 'li', arguments);
        },
        li: function(content){
            var t = this.Tog(true, 'li', skip_arguments(arguments, 1));
            t.cont(content);
            t._isLeaf = true;
            return t;
        },
        A: function(href, value){
            var t = this.Tog(true, 'a', null);
            if(href) t.href(href);
            if(value) t.cont(value);
        },
        a: function(href, value){
            var t = this.Tog(true, 'a', null);
            if(href) t.href(href);
            if(value) t.cont(value);
            t._isLeaf = true;
            return t;
        },
        P: function(content){
            var t = this.Tog(true, 'p', null);
            return t.cont.apply(t, arguments);
        },
        p: function(content){
            var t = this.P.apply(this, arguments);
            t._isLeaf = true;
            return t;
        },
        H1: function(content){
            var t = this.Tog(true, 'h1', null);
            return t.cont.apply(t, arguments);
        },
        h1: function(content){
            var t = this.H1.apply(this, arguments);
            t._isLeaf = true;
            return t;
        },
        H2: function(content){
            var t = this.Tog(true, 'h2', null);
            return t.cont.apply(t, arguments);
        },
        h2: function(content){
            var t = this.H2.apply(this, arguments);
            t._isLeaf = true;
            return t;
        },
        H3: function(content){
            var t = this.Tog(true, 'h3', null);
            return t.cont.apply(t, arguments);
        },
        h3: function(content){
            var t = this.H3.apply(this, arguments);
            t._isLeaf = true;
            return t;
        },
        H4: function(content){
            var t = this.Tog(true, 'h4', null);
            return t.cont.apply(t, arguments);
        },
        h4: function(content){
            var t = this.H4.apply(this, arguments);
            t._isLeaf = true;
            return t;
        },
        H5: function(content){
            var t = this.Tog(true, 'h5', null);
            return t.cont.apply(t, arguments);
        },
        h5: function(content){
            var t = this.H5.apply(this, arguments);
            t._isLeaf = true;
            return t;
        },
        Body: function(param){
            return this.Tog(true, 'body', arguments);
        },
        Head: function(){
            return this.Tog(true, 'head', null);
        },
        Font: function(color, content){
            var t = this.Tog(true, 'font', null);
            if(color) t.attr('color', color);
            t.cont.apply(t, skip_arguments(arguments, 1));
            return t;
        },
        font: function(color, content){
            var t = this.Tog(true, 'font', null);
            if(color) t.attr('color', color);
            t.cont.apply(t, skip_arguments(arguments, 1));
            t._isLeaf = true;
            return t;
        },
        // utils
        map: function(data, callback, extra){
            if(this.hasOwnProperty('_ids')){
                var flag = true;
            } else{
                flag = false;
            }

            if(typeof callback == 'string'){
                callback = tog[callback];
            }

            if(typeof data == 'string'){
                var matches = data.match(/([^\.]+)\.\.([^\.]+)\/(.*)/)
                if(!matches){
                    return this;
                } else {
                    data = [];
                    var f = parseFloat(matches[1].replace(/^\s\s*/, '').replace(/\s\s*$/, ''));
                    var t = parseFloat(matches[2].replace(/^\s\s*/, '').replace(/\s\s*$/, ''));
                    var s = parseFloat(matches[3].replace(/^\s\s*/, '').replace(/\s\s*$/, ''));
                    
                    
                    if(isNaN(f)){
                        f = 0;
                    }
                    if(isNaN(t)){
                        t = 0;
                    }
                    if(isNaN(s)){
                        s = 1;
                    }
                    if((t-f)*s <=0 ){
                        return this;
                    }
                    for(var i = f; i <= t; i+= s){
                        i = Math.round(i * 1000000)/1000000;
                        data[data.length] = i;
                    }
                }
            } else if(typeof data != 'object' || data == null || typeof callback != 'function'){
                return this;
            }

            if(!extra) extra = {
                _this:this
            }
            else extra._this = this;

            if(data instanceof Array){
                for(i = 0; i < data.length; i++){
                    extra._num = i;
                    if(data[i] == undefined) continue;
                    var res = callback(data[i], i, extra);
                    if(flag)
                        this.cont(res);
                }
            } else {
                i = 0;
                for(var key in data){
                    if(data.hasOwnProperty(key)){
                        extra._num = i;
                        i ++;
                        res = callback(data[i], i, extra);
                        if(flag)
                            this.cont(res);
                    }
                }
            }
			
            return this;
        },
        s: function(input){
            if(this.hasOwnProperty('_ids')){
                var flag = true;
            } else{
                flag = false;
            }

            if(input == undefined || input == null){
                if(flag) return this;
                else return '';
            }
			
            var s = [];
            for(var i = 0; i < arguments.length; i++){
                s[s.length] = arguments[i];
            }
            if(flag){
                return this.cont(s);
            } else {
                return s.join('');
            }
        },
        If: function(code, content){
            if(this.hasOwnProperty('_ids')){
                var t = this;
                if(t._isLeaf){
                    t._isLeaf = false;
                    t.up();
                }
            } else {
                t = Tog();
            }
            t.cont('<. if(' , code, '){ .>');
            for(var i = 1; i < arguments.length; i++){
                content = arguments[i];
                var type = typeof content;
                switch(type){
                    case 'string':
                        break;
                    case 'object':
                        if(content != null){
                            if(content.hasOwnProperty('_ids')){
                                content = content.html();
                            } else {
                                content = content.toString();
                            }
                        } else {
                            content = '';
                        }
                        break;
                    default:
                        content = '';
                        break;
                }
                t.cont(content);
            }
            t.cont('<.}.>');

            return t;
        },
        Else: function(content){
            if(this.hasOwnProperty('_ids')){
                var t = this;
                if(t._isLeaf){
                    t._isLeaf = false;
                    t.up();
                }
            } else {
                t = Tog();
            }
            
            t.cont('<. else { .>');
            for(var i = 0; i < arguments.length; i++){
                content = arguments[i];
                var type = typeof content;
                switch(type){
                    case 'string':
                        break;
                    case 'object':
                        if(content != null){
                            if(content.hasOwnProperty('_ids')){
                                content = content.html();
                            } else {
                                content = content.toString();
                            }
                        } else {
                            content = '';
                        }
                        break;
                    default:
                        content = '';
                        break;
                }
                t.cont(content);
            }
            t.cont('<.}.>');

            return t;
        },
        ElseIf: function(code, content){
            if(this.hasOwnProperty('_ids')){
                var t = this;
                if(t._isLeaf){
                    t._isLeaf = false;
                    t.up();
                }
            } else {
                t = Tog();
            }

            t.cont('<. else if(', code, ') { .>');
            for(var i = 1; i < arguments.length; i++){
                content = arguments[i];
                var type = typeof content;
                switch(type){
                    case 'string':
                        break;
                    case 'object':
                        if(content != null){
                            if(content.hasOwnProperty('_ids')){
                                content = content.html();
                            } else {
                                content = content.toString();
                            }
                        } else {
                            content = '';
                        }
                        break;
                    default:
                        content = '';
                        break;
                }
                t.cont(content);
            }
            t.cont('<.}.>');

            return t;
        },
        While: function(code, content){
            if(this.hasOwnProperty('_ids')){
                var t = this;
                if(t._isLeaf){
                    t._isLeaf = false;
                    t.up();
                }
            } else {
                t = Tog();
            }

            t.cont('<. while(', code, ') { .>');
            for(var i = 1; i < arguments.length; i++){
                content = arguments[i];
                var type = typeof content;
                switch(type){
                    case 'string':
                        break;
                    case 'object':
                        if(content != null){
                            if(content.hasOwnProperty('_ids')){
                                content = content.html();
                            } else {
                                content = content.toString();
                            }
                        } else {
                            content = '';
                        }
                        break;
                    default:
                        content = '';
                        break;
                }
                t.cont(content);
            }
            t.cont('<.}.>');

            return t;
        },
        For: function(code, content){
            if(this.hasOwnProperty('_ids')){
                var t = this;
                if(t._isLeaf){
                    t._isLeaf = false;
                    t.up();
                }
            } else {
                t = Tog();
            }

            t.cont('<. for(', code, ') { .>');
            for(var i = 1; i < arguments.length; i++){
                content = arguments[i];
                var type = typeof content;
                switch(type){
                    case 'string':
                        break;
                    case 'object':
                        if(content != null){
                            if(content.hasOwnProperty('_ids')){
                                content = content.html();
                            } else {
                                content = content.toString();
                            }
                        } else {
                            content = '';
                        }
                        break;
                    default:
                        content = '';
                        break;
                }
                t.cont(content);
            }
            t.cont('<.}.>');

            return t;
        },
        Each: function(code, content){
            if(this.hasOwnProperty('_ids')){
                var t = this;
                if(t._isLeaf){
                    t._isLeaf = false;
                    t.up();
                }
            } else {
                t = Tog();
            }

            // check if the sub-var names are defined
            var in_pattern = code.split(' in ');
            
            // getting the declaration of the sub-vars
            if(in_pattern.length > 1){
                // the second part is actually the code
                code = in_pattern[1];
                if(in_pattern[0].indexOf('(') != -1){
                    var_def = in_pattern[0];
                } else {
                    var_def = ['(', in_pattern[0], ', key, _num)'].join('');
                }
            } else {
                var var_def = "($d, key, _num)";
            }
            
            // parsing the code 
            // possibility : [1..2] 0.1 or obj
            
            if(code.match(/\[[^\.]+\.\.[^\.]+\]/)){
                code = ['"', code, '"'].join('')
            }
            
            t.cont('<. ru.map(', code, ', function', var_def, ' { .>');
            for(var i = 1; i < arguments.length; i++){
                content = arguments[i];
                var type = typeof content;
                switch(type){
                    case 'string':
                        break;
                    case 'object':
                        if(content != null){
                            if(content.hasOwnProperty('_ids')){
                                content = content.html();
                            } else {
                                content = content.toString();
                            }
                        } else {
                            content = '';
                        }
                        break;
                    default:
                        content = '';
                        break;
                }
                t.cont(content);
            }
            t.cont('<.});.>');

            return t;
        },
        Code: function(code){
            if(this.hasOwnProperty('_ids')){
                var t = this;
                if(t._isLeaf){
                    t._isLeaf = false;
                    t.up();
                }
            } else {
                t = Tog();
            }
            for(var i = 0; i < arguments.length; i++){
                code = arguments[i];
                var type = typeof content;
                switch(type){
                    case 'string':
                        break;
                    case 'object':
                        if(code != null){
                            if(code.hasOwnProperty('_ids')){
                                code = code.html();
                            } else {
                                code = code.toString();
                            }
                        } else {
                            code = '';
                        }
                        break;
                    default:
                        code = '';
                        break;
                }
                t.cont('<.', code, ';.>');
            }

            return t;
        },
        aIf: function(code, content){
            if(this.hasOwnProperty('_ids')){
                var t = this;
            } else {
                t = Tog();
            }
            t.astr('<. if(' , code, '){ .>');
            for(var i = 1; i < arguments.length; i++){
                content = arguments[i];
                var type = typeof content;
                switch(type){
                    case 'string':
                        break;
                    case 'object':
                        if(content != null){
                            if(content.hasOwnProperty('_ids')){
                                content = content.html();
                            } else {
                                content = content.toString();
                            }
                        } else {
                            content = '';
                        }
                        break;
                    default:
                        content = '';
                        break;
                }
                t.astr(content);
            }
            t.astr('<.}.>');

            return t;
        },
        aElse: function(content){
            if(this.hasOwnProperty('_ids')){
                var t = this;
            } else {
                t = Tog();
            }

            t.astr('<. else { .>');
            for(var i = 0; i < arguments.length; i++){
                content = arguments[i];
                var type = typeof content;
                switch(type){
                    case 'string':
                        break;
                    case 'object':
                        if(content != null){
                            if(content.hasOwnProperty('_ids')){
                                content = content.html();
                            } else {
                                content = content.toString();
                            }
                        } else {
                            content = '';
                        }
                        break;
                    default:
                        content = '';
                        break;
                }
                t.astr(content);
            }
            t.astr('<.}.>');

            return t;
        },
        aElseIf: function(code, content){
            if(this.hasOwnProperty('_ids')){
                var t = this;
            } else {
                t = Tog();
            }

            t.astr('<. else if(', code, ') { .>');
            for(var i = 1; i < arguments.length; i++){
                content = arguments[i];
                var type = typeof content;
                switch(type){
                    case 'string':
                        break;
                    case 'object':
                        if(content != null){
                            if(content.hasOwnProperty('_ids')){
                                content = content.html();
                            } else {
                                content = content.toString();
                            }
                        } else {
                            content = '';
                        }
                        break;
                    default:
                        content = '';
                        break;
                }
                t.astr(content);
            }
            t.astr('<.}.>');

            return t;
        },
        aWhile: function(code, content){
            if(this.hasOwnProperty('_ids')){
                var t = this;
            } else {
                t = Tog();
            }

            t.astr('<. while(', code, ') { .>');
            for(var i = 1; i < arguments.length; i++){
                content = arguments[i];
                var type = typeof content;
                switch(type){
                    case 'string':
                        break;
                    case 'object':
                        if(content != null){
                            if(content.hasOwnProperty('_ids')){
                                content = content.html();
                            } else {
                                content = content.toString();
                            }
                        } else {
                            content = '';
                        }
                        break;
                    default:
                        content = '';
                        break;
                }
                t.astr(content);
            }
            t.astr('<.}.>');

            return t;
        },
        aFor: function(code, content){
            if(this.hasOwnProperty('_ids')){
                var t = this;
            } else {
                t = Tog();
            }

            t.astr('<. for(', code, ') { .>');
            for(var i = 1; i < arguments.length; i++){
                content = arguments[i];
                var type = typeof content;
                switch(type){
                    case 'string':
                        break;
                    case 'object':
                        if(content != null){
                            if(content.hasOwnProperty('_ids')){
                                content = content.html();
                            } else {
                                content = content.toString();
                            }
                        } else {
                            content = '';
                        }
                        break;
                    default:
                        content = '';
                        break;
                }
                t.astr(content);
            }
            t.astr('<.}.>');

            return t;
        },
        aEach: function(code, content){
            if(this.hasOwnProperty('_ids')){
                var t = this;
                if(t._isLeaf){
                    t._isLeaf = false;
                    t.up();
                }
            } else {
                t = Tog();
            }

            // check if the sub-var names are defined
            var in_pattern = code.split(' in ');
            
            // getting the declaration of the sub-vars
            if(in_pattern.length > 1){
                // the second part is actually the code
                code = in_pattern[1];
                if(in_pattern[0].indexOf('(') != -1){
                    var_def = in_pattern[0];
                } else {
                    var_def = ['(', in_pattern[0], ', key, _num)'].join('');
                }
            } else {
                var var_def = "($d, key, _num)";
            }
            
            // parsing the code 
            // possibility : [1..2] 0.1 or obj
            
            if(code.match(/\[[^\.]+\.\.[^\.]+\]/)){
                code = ['"', code, '"'].join('')
            }
            
            t.astr('<. ru.map(', code, ', function', var_def, ' { .>');
            for(var i = 1; i < arguments.length; i++){
                content = arguments[i];
                var type = typeof content;
                switch(type){
                    case 'string':
                        break;
                    case 'object':
                        if(content != null){
                            if(content.hasOwnProperty('_ids')){
                                content = content.html();
                            } else {
                                content = content.toString();
                            }
                        } else {
                            content = '';
                        }
                        break;
                    default:
                        content = '';
                        break;
                }
                t.astr(content);
            }
            t.astr('<.});.>');

            return t;
        },
        aCode: function(code){
            if(this.hasOwnProperty('_ids')){
                var t = this;
            } else {
                t = Tog();
            }
            for(var i = 0; i < arguments.length; i++){
                code = arguments[i];
                var type = typeof content;
                switch(type){
                    case 'string':
                        break;
                    case 'object':
                        if(code != null){
                            if(code.hasOwnProperty('_ids')){
                                code = code.html();
                            } else {
                                code = code.toString();
                            }
                        } else {
                            code = '';
                        }
                        break;
                    default:
                        code = '';
                        break;
                }
                t.astr('<.', code, ';.>');
            }

            return t;
        },
        compile:function(name, extra1, obj){
            // <, data value ,> <. the javascript code .>
            if(!name || typeof name != 'string'){
                return this;
            }
            if(this instanceof _tog){
                obj = extra1;
                extra1 = this.html();
            }
            if(typeof extra1 == 'object' && extra1.hasOwnProperty('_ids')){
                extra1 = extra1.html();
            } else if(typeof extra1 != 'string'){
                throw new Error("No template is provided, compilation error");
            }
            var ps = extra1.split('<.');

            var code = ['this.__tmp_func__ = function($d, $e){ var ru = RU; var $r = [];\
        var $t = this;\
        if(!$e){$e = {}}\
        if($d == undefined || $d == null) $d = {};',
            'if(this.hasOwnProperty("_ids")){var _flag_=true;}else{_flag_=false;}'];

            for(var i = 0; i < ps.length; i++){
                if(i == 0){
                    parseTemplateStr(ps[i], code);
                } else {
                    var sub = ps[i].split('.>');
                    code[code.length] = sub[0];
                    code[code.length] = '\n';
                    if(sub[1]){
                        parseTemplateStr(sub[1], code);
                    }
                }
            }

            code[code.length] = 'if(_flag_){return this.cont($r.join(""));}else{return $r.join("");};}';


            if(typeof obj == 'object' && obj != null){
                obj[name] = eval(code.join(''));
            } else {
                tog['cmp_' + name] = eval(code.join(''));
            }
            return this;
        // end of compile()
        }
    } // end of _tag.prototype


    // for compiling the tog to a function
    function parseTemplateStr(str, code){
        var ps = str.split('<,');

        for(var i = 0; i < ps.length; i ++){
            if(i == 0){
                if(ps[i] != ''){
                    code[code.length] = '$r[$r.length] = "';
                    code[code.length] = ps[i].split('"').join('\\"').split('\n').join('\\n');
                    code[code.length] = '";\n';
                }
            } else {
                var sub = ps[i].split(',>');
                code[code.length] = 'try{$r[$r.length] = ';
                code[code.length] = sub[0];
                code[code.length] = ';}catch(e){}\n';
                if(sub[1]){
                    code[code.length] = '$r[$r.length] = "';
                    code[code.length] = sub[1].split('"').join('\\"').split('\n').join('\\n');
                    code[code.length] = '";\n';
                }
            }
        }
    }

    RU = {
        raw: function(str, str2){
            if(str2 != undefined){
                var res = []
                for(var i = 0; i < arguments.length; i++){
                    res[res.length] = html_escape(arguments[i], true);
                }
                return res.join('');
            } else {
                return html_escape(str, true);
            }
        },
        starts: function(str, prefix, isCaseSensitive){
            if(typeof str != 'string' && typeof prefix != 'string') return false;
            else {
                if(isCaseSensitive == undefined || isCaseSensitive == false){
                    return str.substring(0, prefix.length) === prefix;
                } else {
                    return str.toLowerCase().substring(0, prefix.length) == prefix.toLowerCase();
                }
            }
        },
        ends: function(str, suffix, isCaseSensitive){
            if(typeof str != 'string' && typeof suffix != 'string') return false;
            else {
                if(isCaseSensitive == undefined || isCaseSensitive == false){
                    return str.indexOf(suffix, str.length - suffix.length) !== -1;
                } else {
                    return str.toLowerCase().indexOf(suffix.toLowerCase(), str.length - suffix.length) !== -1;
                }
            }
        },
        trim: function(str){
            if(typeof str != 'string') return str;
            else return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
        },
        map: function(data, callback){
            if(typeof data == 'string'){
                var matches = data.match(/\(([^\.]+)\.\.([^\.]+)\)(.*)/)
                if(!matches){
                    return;
                } else {
                    data = [];
                    var f = parseInt(matches[0].replace(/^\s\s*/, '').replace(/\s\s*$/, ''));
                    var t = parseInt(matches[1].replace(/^\s\s*/, '').replace(/\s\s*$/, ''));
                    var s = parseInt(matches[2].replace(/^\s\s*/, '').replace(/\s\s*$/, ''));
                    
                    if(isNaN(f)){
                        f = 0;
                    }
                    if(isNaN(t)){
                        t = 0;
                    }
                    if(isNaN(s)){
                        s = 1;
                    }
                    if(t-f == 0 || s == 0 || Math.abs(t - f)/(t-f) != Math.abs(s)/s ){
                        return;
                    }
                    for(var i = f; i <= t; i+= s){
                        data[data.length] = i;
                    }
                }
            } else if(typeof data != 'object' || data == null || typeof callback != 'function'){
                return;
            }

            if(data instanceof Array){
                for(i = 0; i < data.length; i++){
                    if(data[i] == undefined) continue;
                    callback(data[i], i, i);
                }
            } else {
                var num = 0;
                for(var key in data){
                    if(data.hasOwnProperty(key)){
                        callback(data[i], key, num);
                        num ++;
                    }
                }
            }
        // end of map()
        }
    }

})()

function Tog(input1, input2){
    var root = new _tog('');
    root._emp = 1;
    root._root = root;
    root._ids = {};
    root._ancs = {};
    root.curr = root;
    if(arguments.length > 0){
        root.Tog.apply(root, arguments);
    }
    return root;
}




